package net.midnighttd.engine.view.sprite;

/**
 * Author: Adam Scarr
 * Date: 19/04/2009
 * Time: 4:10:57 PM
 */
public class Movement {
    private int x,y;
    private double rot;
    private double speed;
    private boolean relativeTranslation;
    private boolean relativeRotation;
    private long duration;
    private int xAtStartOfMovement;
    private int yAtStartOfMovement;
    private double rotAtStartOfMovement;
    private long currentMovementStarted;

    /**
     * Create a new translation.
     * @param x         x location
     * @param y         y location
     * @param speed     Speed in pixels per second.
     * @param relative  If the position is relative (not absolute?)
     */
    public Movement(int x, int y, double speed, boolean relative) {
        this.x = x;
        this.y = y;
        this.rot = 0;
        this.speed = speed;
        this.relativeTranslation = relative;
        this.relativeRotation = true;
    }

    public Movement(double rot, double speed, boolean relative) {
        this.rot = rot;
        this.speed = speed;
        this.x = 0;
        this.y = 0;
        this.relativeRotation = relative;
        this.relativeTranslation = true;
    }

     /**
     * Converts a speed (pixels per second) into a duration in nanoseonds.
     *
     * @return the duration of movement.
     */
    public long getDuration() {
        if(duration == 0) {
            if(x == 0 && y == 0) {
                duration = (long)((rot / speed) * 1000000000);
            } else {
                int length = (int)Math.sqrt(x*x + y*y);
                duration = (long)((length / speed) * 1000000000);
            }
        }
        return duration;
    }

    /**
     * Begin the movement now using the given sprite location.
     * @param x current X location of the sprite.
     * @param y current Y location fo the sprite
     * @param rotation current r
     */
    public void start(int x, int y, double rotation) {
        currentMovementStarted = System.nanoTime();

        // Make sure internal variables are stored as relative displacements.
        if(!relativeTranslation) {
            this.x -= x;
            this.y -= y;
        }

        if(!relativeRotation) {
            this.rot -= rotation;
        }

        xAtStartOfMovement = x;
        yAtStartOfMovement = y;
        rotAtStartOfMovement = rotation;
    }

    public Update getUpdate() {
        Update update = new Update();
        long elapsed = System.nanoTime() - currentMovementStarted;
        if(elapsed >= getDuration()) {
            update.complete = true;
            update.x = xAtStartOfMovement + x;
            update.y = yAtStartOfMovement + y;
            update.rotation = rotAtStartOfMovement + rot;

            return update;
        }

        double completness = (elapsed / (double)getDuration());

        update.x = xAtStartOfMovement + (int)(x * completness);
        update.y = yAtStartOfMovement + (int)(y * completness);
        update.rotation = rotAtStartOfMovement + (rot * completness);

        return update;
    }

    public int getFinalX() {
        return x + xAtStartOfMovement;
    }

    public int getFinalY() {
        return y + yAtStartOfMovement;
    }

    public class Update {
        int x, y;
        double rotation;
        boolean complete;
    }

    public double getRot() {
        return rot;
    }

    public int getY() {
        return y;
    }

    public int getX() {
        return x;
    }
}
